/***************************************************************************
 *   Copyright (C) 2007,2009 by Harm van Eersel, Jason Power               *
 *   devsciurus@xs4all.nl, power.jg@gmail.com                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QtGui>
#include <QAssistantClient>

#include "molecule.h"
#include "mainwindow.h"
#include "molview.h"
#include "molscene.h"
#include "element.h"
#include "settings.h"
#include "fileio.h"
#include "mollibitem.h"
#include "periodictablewidget.h"

#include "pywrapper.h"

#define PROGRAM_NAME "molsKetch"
#define PROGRAM_VERSION "Deuterium"

#define ALT_DOC_PATH ""
#define ALT_LIB_PATH ""
#define ALT_CUSTOM_LIB_PATH ""

#define OB_FILE_FORMATS "All supported types (*.*);;SMILES (*.smi);;MDL Molfile (*.mdl *.mol *.sd *.sdf);;XYZ (*.xyz);;ChemDraw Connection Table (*.ct);;Ghemical (*.gpr)"
#define GRAPHIC_FILE_FORMATS "Scalable Vector Graphics (*.svg);;Portable Network Graphics (*.png);;Windows Bitmap (*.bmp);;Joint Photo Expert Group (*.jpeg)"


// Constructor

MainWindow::MainWindow():ret(false)
{
  // Creating the menus and actions

  createView();
  createToolBoxes();
  createActions();
  //createMenus();
  createToolBars();
  createStatusBar();
  initializeAssistant();

  // Set icon
  QIcon icon;
  icon.addFile(":/images/molsketch.svg");
  icon.addFile(":/images/molsketch.png");
  setWindowIcon(icon);

  // Loading settings
  readSettings();
  setCurrentFile("");

  // Connecting signals and slots
  connect(scene->stack,SIGNAL(cleanChanged(bool)), this, SLOT(documentWasModified( )));
  connect(scene,SIGNAL(selectionChange()), this, SLOT(updateInfoBox()));
//   connect(scene,SIGNAL(newMolecule(QPointF,QString)),this, SLOT(newMolecule(QPointF,QString)));
  connect(scene,SIGNAL(editModeChange(int)),this,SLOT(updateEditMode(int)));

  connect(recentLib,SIGNAL(itemClicked(QListWidgetItem*)),scene,SLOT(setElement(QListWidgetItem*)));
  connect(recentLib,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(updateRecentList(QListWidgetItem*)));
  connect(elementLib,SIGNAL(itemClicked(QListWidgetItem*)),scene,SLOT(setElement(QListWidgetItem*)));
  connect(elementLib,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(updateRecentList(QListWidgetItem*)));
}

MainWindow::MainWindow(Molecule* mol):ret(false)
{
  // Creating the menus and actions

  createView();
  createToolBoxes();
  createActions();
  //createMenus();
  createToolBars();
  createStatusBar();
  initializeAssistant();

  // Set icon
  QIcon icon;
  icon.addFile(":/images/molsketch.svg");
  icon.addFile(":/images/molsketch.png");
  setWindowIcon(icon);

  // Loading settings
  readSettings();
  setCurrentFile("");

  // Connecting signals and slots
  connect(scene->stack,SIGNAL(cleanChanged(bool)), this, SLOT(documentWasModified( )));
  connect(scene,SIGNAL(selectionChange()), this, SLOT(updateInfoBox()));
//   connect(scene,SIGNAL(newMolecule(QPointF,QString)),this, SLOT(newMolecule(QPointF,QString)));
  connect(scene,SIGNAL(editModeChange(int)),this,SLOT(updateEditMode(int)));

  connect(recentLib,SIGNAL(itemClicked(QListWidgetItem*)),scene,SLOT(setElement(QListWidgetItem*)));
  connect(recentLib,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(updateRecentList(QListWidgetItem*)));
  connect(elementLib,SIGNAL(itemClicked(QListWidgetItem*)),scene,SLOT(setElement(QListWidgetItem*)));
  connect(elementLib,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(updateRecentList(QListWidgetItem*)));

  scene->addMolecule(mol);
}

MolScene* MainWindow::getScene()
{
    return scene;
}

// Molecuul manipulation methods
// Molecule* MainWindow::newMolecule(const QPointF& position, const QString& element)
// {
//   // Creating a new molecule object
//   Molecule* mol = new Molecule(0,scene);
// 
//   // Adding the molecule to the scene
//   //   scene->addItem(mol);
//   mol->setPos(position);
// 
//   // Adding a atom to the molecule
//   mol->addAtom(element,position);
// 
//   //   cerr << "Molecule added \n";
// 
//   return mol;
// }


// Event handlers

void MainWindow::closeEvent(QCloseEvent *event)
{
  /*if (maybeSave())
    {
      writeSettings();
      if (assistantClient) assistantClient->closeAssistant();
      event->accept();
    }
  else
    {
      event->ignore();
    }*/

  //Calls the python callback function!
  molsketch_return(this);
}

void MainWindow::newFile()
{
  if (maybeSave())
    {
      scene->clear();
      // Resetting the view
      setCurrentFile("");
      molView->resetMatrix();
//       setWindowModified(false);
    }
}

void MainWindow::open()
{
  if (maybeSave())
    {
//       QFileDialog dialog(this);
//       dialog.(tr("Open - molsKetch"));
//       dialog.setFilter(tr(OB_FILE_FORMATS));
//       dialog.selectFilter(tr("Chemical Markup Language (*.mol)"));
//       dialog.setFileMode(QFileDialog::ExistingFile);
//       QString fileName;
//       if (dialog.exec()) fileName = dialog.selectedFiles()[0];
      QString fileName = QFileDialog::getOpenFileName(this,tr("Open - molsKetch"),QDir::homePath(),
      tr(OB_FILE_FORMATS));
      if (!fileName.isEmpty())
        {
          // Start a new document
          scene->clear();

          Molecule* mol = molsKetch::loadFile(fileName);

          if (mol)
            {
              // Add molecule to scene
              if (mol->canSplit())
                {
                  QList<Molecule*> molList = mol->split();
                  foreach(Molecule* mol,molList) scene->addItem(mol);
                }
              else
                {
                  scene->addItem(mol);
                }
              
              
              // Updating view
              setCurrentFile(fileName);
//               setWindowModified(false);
            }
          else
            {
              // Display error message if load fails
              QMessageBox::critical(this,tr(PROGRAM_NAME),tr("Error while loading file"),QMessageBox::Ok,QMessageBox::Ok);
            }
        }
    }
}

bool MainWindow::save()
{
  if (curFile.isEmpty())
    {
      return saveAs();
    }
  else
    {
      if (molsKetch::saveFile(curFile,scene))
      	{
      	  scene->stack->setClean();
      	}
      else
      	return false;
    }
//   setWindowModified(false);
}

bool MainWindow::saveAs()
{
  QString fileName = QFileDialog::getSaveFileName(this,tr("Save as - molsKetch"),QDir::homePath(),tr(OB_FILE_FORMATS));
  if (fileName.isEmpty()) return false;
  if (molsKetch::saveFile(fileName,scene))
    {
      setCurrentFile(fileName);
//       setWindowModified(false);
      scene->stack->setClean();
      return true;
    }
  else
    {
      // Display error message if saving fails
      QMessageBox::critical(this,tr(PROGRAM_NAME),tr("Invalid name or unknown file type"),QMessageBox::Ok,QMessageBox::Ok);

      return false;
    }
}

bool MainWindow::importDoc()
{
  QString fileName = QFileDialog::getOpenFileName(this,tr("Import - molsKetch"),QDir::homePath(),tr(OB_FILE_FORMATS));
  if (!fileName.isEmpty())
    {
      Molecule* mol = molsKetch::loadFile(fileName);
      if (mol)
        {
          scene->addMolecule(mol);
          return true;
        }
      else
        {
          // Display error message if load fails
          QMessageBox::critical(this,tr(PROGRAM_NAME),tr("Error while loading file"),QMessageBox::Ok,QMessageBox::Ok);
          return false;
        }
    }
  return false;
}

bool MainWindow::exportDoc()
{
  // Getting the filename
  QString fileName = QFileDialog::getSaveFileName(this,tr("Export - molsKetch"),QDir::homePath(),tr(GRAPHIC_FILE_FORMATS));

  // Abort if filename is empty
  if (fileName.isEmpty()) return false;

  // Try to export the file
  if (fileName.endsWith(".svg")) return molsKetch::saveToSVG(fileName,scene);

  if (molsKetch::exportFile(fileName,scene))
    {
      return true;
    }
  else
    {
      QMessageBox::critical(this,tr(PROGRAM_NAME),tr("Error while exporting file"),QMessageBox::Ok,QMessageBox::Ok);
      return false;
    }
}

bool MainWindow::print()
{
  // Creating a new printerobject
  QPrinter printer(QPrinter::HighResolution);

  // Prompt for the printoptions
  QPrintDialog printDialog(&printer, this);

  // Try to print the scene
  if (printDialog.exec() == QDialog::Accepted)
    {
      if (molsKetch::printFile(printer,scene))
      {
      	return true;
      }
      else
      {
      	QMessageBox::critical(this,tr(PROGRAM_NAME),tr("Error while printing file"),QMessageBox::Ok,QMessageBox::Ok);
      	return false;
      }
    }
  else
    {
      return false;
    }
}


void MainWindow::setAddMode()
{
  scene->setEditMode(MolScene::AddMode);
}

void MainWindow::setDelMode()
{
  scene->setEditMode(MolScene::DelMode);
}

void MainWindow::setMoveMode()
{
  scene->setEditMode(MolScene::MoveMode);
}

void MainWindow::zoomIn()
{
  molView->scale(2,2);
}

void MainWindow::zoomOut()
{
  molView->scale(0.5,0.5);
}

void MainWindow::zoomReset()
{
  molView->resetMatrix();
}

void MainWindow::zoomFit()
{
  molView->fitInView(scene->itemsBoundingRect(),Qt::KeepAspectRatio);
}

void MainWindow::assistant()
{
  QFileInfo file(ALT_DOC_PATH + QString("/index.html"));
  if (!file.exists()) file.setFile(QApplication::applicationDirPath() + "/doc/en/index.html");
  if (!file.exists()) file.setFile(QApplication::applicationDirPath() + "/../share/doc/molsketch/doc/en/index.html");
  assistantClient->showPage(file.absoluteFilePath());
}

void MainWindow::about()
{
  QMessageBox::about(this, tr("About"),
                     tr("<H3>About molsKetch</H3> <P> molsKetch is an program for drawing molecular structures developed by Harm van Eersel at the <A href=\"http://www.tue.nl\">Eindhoven University of Technology</A>.<P> For more info check <A href=\"http://molsketch.sourceforge.net\">http://molsketch.sourceforge.net</A>  <P> It is <A href=\"http://www.gnu.org/philosophy/free-sw.html\">free software</A> and available under the <A>GPL</A>. <P> Special thanks to: <UL><LI>Dr. H. Zantema (coach)</LI> <LI> Davy van der Vaart (tester)</LI><LI>Frans Visscher (tester)</LI><LI>Carsten Niehaus (reviewer)</LI></UL>Copyright 2007 - Harm van Eersel"));
}

void MainWindow::documentWasModified()
{
  setWindowModified(!scene->stack->isClean());
}

void MainWindow::updateEditMode(int mode)
{
  // Change the buttonstates depending on the edit mode
  switch (mode)
    {
    case MolScene::AddMode:
      addModeAct->setChecked(true);
      delModeAct->setChecked(false);
      moveModeAct->setChecked(false);
      molView->setDragMode(QGraphicsView::NoDrag);
      statusBar()->showMessage(tr("Left Click: add atom, Drag: add bond, Click on bond: change order, Shift + Left Click on bond: change type, Right Click: remove item"));
      break;
    case MolScene::DelMode:
      addModeAct->setChecked(false);
      delModeAct->setChecked(true);
      moveModeAct->setChecked(false);
      molView->setDragMode(QGraphicsView::NoDrag);
      statusBar()->showMessage(tr("Click on an item to delete it. Double click on an molecule to delete it."));
      break;
    case MolScene::MoveMode:
      addModeAct->setChecked(false);
      delModeAct->setChecked(false);
      moveModeAct->setChecked(true);
      molView->setDragMode(QGraphicsView::RubberBandDrag);
      statusBar()->showMessage(tr("Click on an item to select it. Drag to move selected items."));
      break;
    }
}

// Widget creators

void MainWindow::createActions()
{    
  newAct = new QAction(QIcon(":/images/filenew.png"), tr("&New"),this);
  newAct->setShortcut(tr("Ctrl+N"));
  newAct->setStatusTip(tr("Create a new file"));
  connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

  openAct = new QAction(QIcon(":/images/fileopen.png"),tr("&Open..."), this);
  openAct->setShortcut(tr("Ctrl+O"));
  openAct->setStatusTip(tr("Open an existing file"));
  connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

  saveAct = new QAction(QIcon(":/images/filesave.png"), tr("&Save"), this);
  saveAct->setShortcut(tr("Ctrl+S"));
  saveAct->setStatusTip(tr("Save the document to disk"));
  connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));

  saveAsAct = new QAction(QIcon(":/images/filesaveas.png"),tr("Save &As..."), this);
  saveAsAct->setStatusTip(tr("Save the document under a new name"));
  connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));

  importAct = new QAction(QIcon(":/images/fileimport.png"),tr("&Import..."), this);
  importAct->setShortcut(tr("Ctrl+I"));
  importAct->setStatusTip(tr("Insert an existing molecule into the document"));
  connect(importAct, SIGNAL(triggered()), this, SLOT(importDoc()));

  exportAct = new QAction(QIcon(":/images/fileexport.png"),tr("&Export..."), this);
  exportAct->setShortcut(tr("Ctrl+E"));
  exportAct->setStatusTip(tr("Export the current document as a picture"));
  connect(exportAct, SIGNAL(triggered()), this, SLOT(exportDoc()));

  printAct = new QAction(QIcon(":/images/fileprint.png"),tr("&Print..."), this);
  printAct->setShortcut(tr("Ctrl+P"));
  printAct->setStatusTip(tr("Print the current document"));
  connect(printAct, SIGNAL(triggered()), this, SLOT(print()));

  exitAct = new QAction(QIcon(":/images/exit.png"),tr("E&xit"), this);
  exitAct->setShortcut(tr("Ctrl+Q"));
  exitAct->setStatusTip(tr("Exit the application"));
  connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

  // Edit actions
  undoAct = scene->stack->createUndoAction(this);
  undoAct->setIcon(QIcon(":/images/undo.png"));
  undoAct->setShortcut(tr("Ctrl+Z"));
  undoAct->setStatusTip(tr("Undo the last action"));

  redoAct = scene->stack->createRedoAction(this);
  redoAct->setIcon(QIcon(":/images/redo.png"));
  redoAct->setShortcut(tr("Ctrl+Shift+Z"));
  redoAct->setStatusTip(tr("Redo the last action"));

  cutAct = new QAction(QIcon(":/images/editcut.png"), tr("Cu&t"), this);
  cutAct->setShortcut(tr("Ctrl+X"));
  cutAct->setStatusTip(tr("Cut the current selection's contents to the "
                          "clipboard"));
  connect(cutAct, SIGNAL(triggered()), scene, SLOT(cut()));

  copyAct = new QAction(QIcon(":/images/editcopy.png"), tr("&Copy"), this);
  copyAct->setShortcut(tr("Ctrl+C"));
  copyAct->setStatusTip(tr("Copy the current selection's contents to the "
                           "clipboard"));
  connect(copyAct, SIGNAL(triggered()), scene, SLOT(copy()));

  pasteAct = new QAction(QIcon(":/images/editpaste.png"), tr("&Paste"), this);
  pasteAct->setShortcut(tr("Ctrl+V"));
  pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
                            "selection"));
  connect(pasteAct, SIGNAL(triggered()), scene, SLOT(paste()));

  selectAllAct = new QAction(QIcon(""), tr("&Select all"),this);
  selectAllAct->setShortcut(tr("Ctrl+A"));
  selectAllAct->setStatusTip(tr("Selects all elements on the scene"));
  connect(selectAllAct, SIGNAL(triggered()), scene, SLOT(selectAll()));

  addModeAct = new QAction(QIcon(":/images/edit.png"), tr("&Add Mode"), this);
  addModeAct->setCheckable(true);
  addModeAct->setShortcut(tr("F5"));
  addModeAct->setStatusTip(tr("Go to the atom addition mode"));
  connect(addModeAct, SIGNAL(triggered()), this, SLOT(setAddMode()));

  delModeAct = new QAction(QIcon(":/images/eraser.png"), tr("&Delete Mode"), this);
  delModeAct->setCheckable(true);
  delModeAct->setShortcut(tr("F6"));
  delModeAct->setStatusTip(tr("Go to the atom deletion mode"));
  connect(delModeAct, SIGNAL(triggered()), this, SLOT(setDelMode()));

  moveModeAct = new QAction(QIcon(":/images/move.png"), tr("&Move mode"), this);
  moveModeAct->setCheckable(true);
  moveModeAct->setShortcut(tr("F7"));
  moveModeAct->setStatusTip(tr("Go to the molecule move mode"));
  connect(moveModeAct, SIGNAL(triggered()), this, SLOT(setMoveMode()));

  alignAct = new QAction(QIcon(""), tr("Align to grid"), this);
  alignAct->setStatusTip(tr("Align all elements on the scene to the grid"));
  connect(alignAct, SIGNAL(triggered()), scene, SLOT(alignToGrid()));

  prefAct = new QAction(QIcon(""),tr("Edit Pre&ferences..."),this);
  prefAct->setShortcut(tr("Ctrl+F"));
  prefAct->setStatusTip(tr("Edit your preferences"));
  connect(prefAct, SIGNAL(triggered()), this, SLOT(editPref()));

  // Zoom actions
  zoomInAct = new QAction(QIcon(":/images/viewmag+.png"),tr("Zoom &In"), this);
  zoomInAct->setShortcut(tr("Ctrl++"));
  zoomInAct->setStatusTip(tr("Zoom in on the canvas"));
  connect(zoomInAct, SIGNAL(triggered()), this, SLOT(zoomIn()));

  zoomOutAct = new QAction(QIcon(":/images/viewmag-.png"),tr("Zoom &Out"), this);
  zoomOutAct->setShortcut(tr("Ctrl+-"));
  zoomOutAct->setStatusTip(tr("Zoom out on the canvas"));
  connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOut()));

  zoomResetAct = new QAction(QIcon(":/images/viewmag1.png"),tr("Zoom &Reset"), this);
  zoomResetAct->setShortcut(tr("Ctrl+="));
  zoomResetAct->setStatusTip(tr("Reset the zoom level"));
  connect(zoomResetAct, SIGNAL(triggered()), this, SLOT(zoomReset()));

  zoomFitAct = new QAction(QIcon(":/images/viewmagfit.png"),tr("Zoom &Fit"), this);
  zoomFitAct->setShortcut(tr("Ctrl+*"));
  zoomFitAct->setStatusTip(tr("Fit to screen"));
  connect(zoomFitAct, SIGNAL(triggered()), this, SLOT(zoomFit()));

  // Help actions
  helpContentsAct = new QAction(QIcon(":/images/contents.png"),tr("&Help Contents..."), this);
  helpContentsAct->setShortcut(tr("F1"));
  helpContentsAct->setStatusTip(tr("Show the application's help contents"));
  connect(helpContentsAct, SIGNAL(triggered()), this, SLOT(assistant()));
  
  submitBugAct = new QAction(QIcon(""),tr("Submit &Bug..."), this);
  submitBugAct->setStatusTip(tr("Open the browser with the bug tracker"));
  connect(submitBugAct, SIGNAL(triggered()), this, SLOT(submitBug()));

  aboutAct = new QAction(QIcon(":/images/help.png"),tr("&About"), this);
  aboutAct->setStatusTip(tr("Show the application's About box"));
  connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

  aboutQtAct = new QAction(tr("About &Qt"), this);
  aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
  connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
  
  //DB actions
  doneAct = new QAction(tr("Done Editing"), this);
  doneAct->setStatusTip(tr("Finish editing and return to OriginDB"));
  connect(doneAct, SIGNAL(triggered()), this, SLOT(returnToPy()));
  
  cancelAct = new QAction(tr("Cancel Editing"), this);
  cancelAct->setStatusTip(tr("Cancel editing and return to OriginDB"));
  connect(cancelAct, SIGNAL(triggered()), this, SLOT(close()));

  // Setting actions in their initial states
  cutAct->setEnabled(false);
  copyAct->setEnabled(false);
  pasteAct->setEnabled(false);
  addModeAct->setChecked(true);
  connect(scene, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
  connect(scene, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
  connect(scene, SIGNAL(pasteAvailable(bool)), pasteAct, SLOT(setEnabled(bool)));
}


void MainWindow::createMenus()
{
  fileMenu = menuBar()->addMenu(tr("&File"));
  fileMenu->addAction(newAct);
  fileMenu->addAction(openAct);
  fileMenu->addAction(saveAct);
  fileMenu->addAction(saveAsAct);
  fileMenu->addSeparator();
  fileMenu->addAction(importAct);
  fileMenu->addAction(exportAct);
  fileMenu->addAction(printAct);
  fileMenu->addSeparator();
  fileMenu->addAction(exitAct);

  editMenu = menuBar()->addMenu(tr("&Edit"));
  editMenu->addAction(undoAct);
  editMenu->addAction(redoAct);
  editMenu->addSeparator();
  editMenu->addAction(cutAct);
  editMenu->addAction(copyAct);
  editMenu->addAction(pasteAct);
  editMenu->addSeparator();
  editMenu->addAction(selectAllAct);
  editMenu->addAction(alignAct);
  editMenu->addSeparator();
  editMenu->addAction(addModeAct);
  editMenu->addAction(delModeAct);
  editMenu->addAction(moveModeAct);
  editMenu->addSeparator();
  editMenu->addAction(prefAct);

  viewMenu = menuBar()->addMenu(tr("&View"));
  viewMenu->addAction(zoomInAct);
  viewMenu->addAction(zoomOutAct);
  viewMenu->addAction(zoomResetAct);
  viewMenu->addAction(zoomFitAct);

  menuBar()->addSeparator();

  helpMenu = menuBar()->addMenu(tr("&Help"));
  helpMenu->addAction(helpContentsAct);
  helpMenu->addSeparator();
  helpMenu->addAction(submitBugAct);
  helpMenu->addSeparator();
  helpMenu->addAction(aboutAct);
  helpMenu->addAction(aboutQtAct);
}

void MainWindow::createToolBars()
{
  fileToolBar = addToolBar(tr("File"));
//   fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
  fileToolBar->addAction(newAct);
  fileToolBar->addAction(openAct);
  fileToolBar->addAction(saveAct);
  fileToolBar->addAction(importAct);
  fileToolBar->addAction(exportAct);
  fileToolBar->addAction(printAct);

  editToolBar = addToolBar(tr("Edit"));
//   editToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
  editToolBar->addAction(undoAct);
  editToolBar->addAction(redoAct);
  editToolBar->addSeparator();
  editToolBar->addAction(cutAct);
  editToolBar->addAction(copyAct);
  editToolBar->addAction(pasteAct);
  editToolBar->addSeparator();
  editToolBar->addAction(addModeAct);
  editToolBar->addAction(delModeAct);
  editToolBar->addAction(moveModeAct);

  zoomToolBar = addToolBar(tr("Zoom"));
//   zoomToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
  zoomToolBar->addAction(zoomInAct);
  zoomToolBar->addAction(zoomOutAct);
  zoomToolBar->addAction(zoomResetAct);
  zoomToolBar->addAction(zoomFitAct);

  DBToolBar = addToolBar(tr("OriginDB"));
  DBToolBar->addAction(doneAct);
  DBToolBar->addAction(cancelAct);
}

void MainWindow::createStatusBar()
{
  statusBar()->showMessage(tr("Ready"));
}

void MainWindow::createToolBoxes()
{
  // Creating the dockwidgets
  toolBoxDock = new QDockWidget(tr("Toolbox"));
  toolBoxDock->setMinimumWidth(270);
  infoDock = new QDockWidget(tr("Infobox"));

  // Create libraries
  recentLib = new QListWidget;
  elementLib = new PeriodicTableWidget;
  genericLib = new QListWidget;
  customLib = new QListWidget;

  QPushButton* addButton = new QPushButton(tr("Add..."));
  QPushButton* delButton = new QPushButton(tr("Delete"));

  // Setting the views
  recentLib->setViewMode(QListView::IconMode);
  recentLib->setMovement(QListView::Static);
  recentLib->setResizeMode(QListWidget::Adjust);
  recentLib->setAlternatingRowColors(true);

  genericLib->setAlternatingRowColors(true);
  genericLib->setIconSize(QSize(64,64));

  customLib->setAlternatingRowColors(true);
  customLib->setIconSize(QSize(64,64));

  // Adding common elements
  QStringList celements;
  celements << "H" << "C" << "N" << "O" << "Cl" << "F" << "P" << "R" << "+" << "-";
  recentLib->addItems(celements);

  // Declaring variables
  QDir dir;
  Molecule* mol;

  // Loading generic molecules
  dir.setPath(ALT_LIB_PATH);
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) genericLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }
  
  dir.setPath(QDir::homePath() + "/.molsketch/library");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) genericLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }

  dir.setPath(QApplication::applicationDirPath() + "/../share/molsketch/library");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) genericLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }

  dir.setPath(QApplication::applicationDirPath() + "/library");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) genericLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }

  // Loading custom molecules
  dir.setPath(ALT_CUSTOM_LIB_PATH);
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) customLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }
  
  dir.setPath(QDir::homePath() + "/.molsketch/library/custom");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) customLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }

  dir.setPath(QApplication::applicationDirPath() + "/../share/molsketch/library/custom");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) customLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }

  dir.setPath(QApplication::applicationDirPath() + "/library/custom");
  for (int i = 0; i < dir.count(); i++)
    {
      mol = molsKetch::loadFile(dir.filePath(dir[i]));
      if (mol) customLib->addItem(new MolLibItem(mol,dir.filePath(dir[i])));
    }


  // Composing customLib
  QHBoxLayout* hLayout = new QHBoxLayout;
  hLayout->addWidget(addButton);
  hLayout->addWidget(delButton);
  QVBoxLayout* vLayout = new QVBoxLayout;
  vLayout->addWidget(customLib);
  vLayout->addLayout(hLayout);

  QFrame* frame = new QFrame;
  frame->setLayout(vLayout);

  // Create a library toolbox and add the libraries
  toolBox = new QToolBox;
  toolBox->addItem(recentLib,tr("Recent Items"));
  toolBox->addItem(elementLib,tr("Elements"));
  toolBox->addItem(genericLib,tr("Generic Molecules"));
  toolBox->addItem(frame,tr("Custom Molecules"));
  toolBoxDock->setWidget(toolBox);

  // Create and add a infowidget
  infoText = new QTextEdit;
  infoText->setReadOnly(true);
  infoDock->setWidget(infoText);

  // Placing the dockwidgets in their default position
  addDockWidget(Qt::LeftDockWidgetArea,toolBoxDock);
  addDockWidget(Qt::LeftDockWidgetArea,infoDock);

  // Connecting signals and slots
  connect(genericLib,SIGNAL(itemDoubleClicked(QListWidgetItem*)),scene,SLOT(addMolecule(QListWidgetItem*)));
//   connect(genericLib,SIGNAL(itemClicked(QTableWidgetItem*)),this,SLOT(updateRecentList(QTableWidgetItem*)));
  connect(customLib,SIGNAL(itemDoubleClicked(QListWidgetItem*)),scene,SLOT(addMolecule(QListWidgetItem*)));
//     connect(customLib,SIGNAL(itemClicked(QTableWidgetItem*)),this,SLOT(updateRecentList(QTableWidgetItem*)));
  connect(addButton,SIGNAL(released()),this,SLOT(addCustomMol()));
  connect(delButton,SIGNAL(released()),this,SLOT(delCustomMol()));
}

void MainWindow::addCustomMol()
{
  foreach(QGraphicsItem* item, scene->selectedItems())
  {
    if (item->type() == Molecule::Type)
      {
        Molecule* mol = dynamic_cast<Molecule*>(item);
        QString name = QInputDialog::getText(this,tr("Enter a name"),tr("Enter a name for this item:"),QLineEdit::Normal,mol->formula());
        customLib->addItem(new MolLibItem(mol,name));
      }
  }
}

void MainWindow::delCustomMol()
{
  if (QMessageBox::warning(this,tr("Are you sure?"),tr("Do you really want to delete this item?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::No) == QMessageBox::Yes)
    {
      MolLibItem* item = dynamic_cast<MolLibItem*>(customLib->currentItem());
      QFile::remove(item->getFileName().filePath());
      delete item;
    }
}

void MainWindow::createView()
{
  // Create new scene
  scene = new MolScene(this);

  // Create and set view
  molView = new MolView(scene);
  molView->setRenderHints(QPainter::Antialiasing);
//   	molView->setDragMode(QGraphicsView::ScrollHandDrag);
//   molView->setAlignment ( Qt::AlignLeft | Qt::AlignTop );
  molView->setResizeAnchor(QGraphicsView::AnchorViewCenter);
  molView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);

  // Placing the view widget
  setCentralWidget(molView);
  molView->show();
  
  // Resize scene
//   QRectF sizerect(QPointF(-molView->size().width()/2,-molView->size().height()/2),molView->size());
  QRectF sizerect(-5000,-5000,10000,10000);
  scene->setSceneRect(sizerect);
}

void MainWindow::initializeAssistant()
{
  assistantClient = new QAssistantClient("", this);

  QStringList arguments;
  QFileInfo file(ALT_DOC_PATH + QString("/molsketch.adp"));
  if (!file.exists()) file.setFile(QApplication::applicationDirPath() + "/doc/en/molsketch.adp");
  if (!file.exists()) file.setFile(QApplication::applicationDirPath() + "/../share/doc/molsketch/doc/en/molsketch.adp");

  arguments << "-profile" << file.absoluteFilePath();
  assistantClient->setArguments(arguments);
}

// Auxillary methods

void MainWindow::readSettings()
{
  // Reading the settings
  QSettings settings(PROGRAM_NAME, QString(PROGRAM_NAME) + QString(PROGRAM_VERSION));

  // Setting the window position
  QPoint pos = settings.value("pos",QPoint(100,100)).toPoint();
  QSize size = settings.value("size",QSize(800,600)).toSize();
  resize(size);
  move(pos);

  // Loading paths
  libpath = settings.value("libpath","/usr/share/molsketch/library").toString();

  // Load the preferences
  scene->setAtomSize(settings.value("atomsize",30).toDouble());
  scene->setAutoAddHydrogen(settings.value("autoaddhydrogen",true).toBool());
  scene->setBondLength(settings.value("bondlength",40).toDouble());
  scene->setBondAngle(settings.value("bondangle",12).toInt());
  scene->setCarbonVisible(settings.value("carbonvisible",false).toBool());
  scene->setHydrogenVisible(settings.value("hydrogenvisible",true).toBool());
  scene->setChargeVisible(settings.value("chargevisible",true).toBool());
}

void MainWindow::writeSettings()
{
  // Saving the settings
  QSettings settings(PROGRAM_NAME, QString(PROGRAM_NAME) + QString(PROGRAM_VERSION));

  // Saving the window position
  settings.setValue("pos",pos());
  settings.setValue("size",size());

  // Saving paths
  settings.setValue("libpath",libpath);

  // Saving preferences
  settings.setValue("atomsize",scene->atomSize());
  settings.setValue("autoaddhydrogen",scene->autoAddHydrogen());
  settings.setValue("bondlength",scene->bondLength());
  settings.setValue("bondangle",scene->bondAngle());
  settings.setValue("carbonvisible",scene->carbonVisible());
  settings.setValue("hydrogenvisible",scene->hydrogenVisible());
  settings.setValue("chargevisible",scene->chargeVisible());
}


bool MainWindow::maybeSave()
{
  ///TODO
  if (isWindowModified())
    {
      QMessageBox::StandardButton ret;
      ret = QMessageBox::warning(this,tr(PROGRAM_NAME),
                                 tr("This document has been modified.\n"
                                    "Do you want to save your changes?"),
                                 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
      if (ret == QMessageBox::Save)
        return save();
      else if (ret == QMessageBox::Cancel)
        return false;
    }
  return true;
}

void MainWindow::setCurrentFile(const QString &fileName)
{
  // Synthesizing the correct name
  curFile = fileName;
  QString shownName;
  if (curFile.isEmpty())
    shownName = tr("untitled.mol");
  else
    shownName = strippedName(curFile);

  // Setting the windowtitle
  setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr(PROGRAM_NAME)));
}

QString MainWindow::strippedName(const QString &fullFileName)
{
  return QFileInfo(fullFileName).fileName();
}


void MainWindow::updateRecentList( QListWidgetItem* element )
{
  //   recentLib->addItem(element);
  bool unique = true;
  for (int i = 0; i < recentLib->count(); i++)
    if (recentLib->item(i)->text() == element->text()) unique = false;
  if (unique) recentLib->addItem(element->text());
}

void MainWindow::updateRecentList( QTableWidgetItem * element )
{
  bool unique = true;
  for (int i = 0; i < recentLib->count(); i++)
    if (recentLib->item(i)->text() == element->text()) unique = false;
  if (unique) recentLib->addItem(element->text());
}

void MainWindow::updateInfoBox( )
{
  // Initializing variables
  QString formula;
  int molecules = 0;
  int atoms = 0;
  int bonds = 0;
  qreal weight = 0;
  int charge = 0;

  // Get the selected molecules and load the values
  QGraphicsItem* item;

  // Check if selected
  foreach(item,scene->selectedItems()) if (item->type() == Molecule::Type)
    {
      // Get the molecule
      Molecule* mol = dynamic_cast<Molecule*>(item);

      // Create formula
      QString rawFormula = mol->formula();
      QChar rawChar;
      foreach (rawChar,rawFormula)
      if (rawChar.isDigit())formula += "<sub>" + QString(rawChar) + "</sub>";
      else formula += rawChar;

      // Add charge
      formula += "<sup>" + mol->chargeID() + "</sup>" + " ";

      // Loading values
      molecules += 1;
      weight += mol->weight();
      atoms += mol->atoms().count();
      bonds += mol->bonds().count();
      charge += mol->charge();
    }

  // Else check for focussed item
  if (formula.isEmpty() && scene->focusItem())
    {
      item = scene->focusItem();

      // Get the molecule
      Molecule* mol = dynamic_cast<Molecule*>(item);

      // Create formula
      QString rawFormula = mol->formula();
      QChar rawChar;
      foreach (rawChar,rawFormula)
      if (rawChar.isDigit())formula += "<sub>" + QString(rawChar) + "</sub>";
      else formula += rawChar;

      // Add charge
      formula += "<sup>" + mol->chargeID() + "</sup>" + " ";

      // Loading values
      molecules += 1;
      weight += mol->weight();
      atoms += mol->atoms().count();
      bonds += mol->bonds().count();
      charge += mol->charge();
    }

  // Else failsafe
  if (formula.isEmpty()) formula = tr("Non selected");
  infoText->setText("<h1>" + formula + "\n" + "</h1>");

  infoText->append("<h3>" + tr("Number of molecules: ") + QString::number(molecules) + "<P>" + tr("Total weight: ") + QString::number(weight) +"<P>" + tr("Total charge: ")+ QString::number(charge) + "<P>" + tr("Number of atoms: ") + QString::number(atoms) + "<P>" + tr("Number of bonds: ") + QString::number(bonds) + "<P>" + tr("Number of items: ") + QString::number(scene->items().count()) + "<P>" + "</h3>");

}

void MainWindow::editPref( )
{
  // Opens the settings dialog
  SettingsDialog dialog(scene);
  dialog.exec();
}

void MainWindow::submitBug()
{
  // Opens a browser with the bug tracker
  QDesktopServices::openUrl(QUrl("http://sourceforge.net/tracker/?func=add&group_id=191562&atid=937880"));
}

void MainWindow::returnToPy()
{
  this->ret = true;
  this->close();
}

bool MainWindow::getRet()
{
  return ret;
}